﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Demo.Entity;
using Demo.Helper;
using MetroFramework.Forms;
using NModbus;
using NModbus.Device;
using NModbus.Extensions.Enron;

namespace Demo.Page
{
    public partial class OperationForm : MetroForm
    {
        PlcHelper Instance = PlcHelper.Instance;

        public OperationForm()
        {
            InitializeComponent();
        }

        /*日志输出*/
        #region
        /// <summary>
        /// 在Listview添加日志
        /// </summary>
        /// <param name="log">日志实体</param>
        /// <param name="index">ImageList下标</param>
        public void WriteLog(Log log, int index)
        {
            if (listView1.InvokeRequired)
            {
                listView1.Invoke(
                    new Action(() =>
                    {
                        ListViewItem item1 = new ListViewItem("", index);
                        item1.SubItems.AddRange(
                            new string[] { log.logDateTime.ToString(), log.logInfo }
                        );
                        listView1.Items.Add(item1);
                    })
                );
            }
            else
            {
                ListViewItem item1 = new ListViewItem("", index);
                item1.SubItems.AddRange(new string[] { log.logDateTime.ToString(), log.logInfo });
                listView1.Items.Add(item1);
            }
        }
        #endregion

        public Thread thread1;

        /// <summary>
        /// 连接PLC按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_PlcConnect_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txt_IpAddress.Text))
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请输入ip地址" }, 0);
                MessageBox.Show("请输入ip地址");
                return;
            }

            if (string.IsNullOrEmpty(txt_Port.Text) || !int.TryParse(txt_Port.Text, out int port))
            {
                MessageBox.Show("请输入有效的端口号");
                return;
            }

            // 判断是否已经连接
            if (Instance.isConnected == true)
            {
                MessageBox.Show("已经连接");
                return;
            }

            // 尝试连接PLC
            bool connectSuccess = Instance.Initialize(txt_IpAddress.Text, port);
            signalPLC.Value = connectSuccess ? 5 : 1;

            // 记录日志
            int index = connectSuccess ? 1 : 0;
            WriteLog(
                new Log()
                {
                    logDateTime = DateTime.Now,
                    logInfo = connectSuccess ? "plc连接成功" : "plc连接失败",
                },
                index
            );

            if (connectSuccess)
            {
                // 创建并启动读取线程
                thread1 = new Thread(new ThreadStart(ReadPlcData))
                {
                    IsBackground = true,
                    Name = "读取plc线程",
                };
                thread1.Start();
            }
        }

        /// <summary>
        /// 读PLC数据
        /// </summary>
        private void ReadPlcData()
        {
            while (true)
            {
                try
                {
                    //读取急停 X11 IO点给反了  false 打开了急停
                    bool[] readResult = Instance.modbusMaster.ReadCoils(1, 1200, 11);

                    //变频器状态 D100
                    ushort[] read = Instance.modbusMaster.ReadHoldingRegisters(1, 100, 1);

                    // 模组使能标志 M10
                    bool[] readBoll = Instance.modbusMaster.ReadCoils(1, 2010, 1);

                    //设备总报警  M4
                    bool[] readAlarmBoll = Instance.modbusMaster.ReadCoils(1, 2004, 1);

                    //读取气缸 Y5
                    bool[] readResult2 = Instance.modbusMaster.ReadCoils(1, 5, 2);

                    this.BeginInvoke(
                        new Action(() =>
                        {
                            light_Stop.State = (Sunny.UI.UILightState)(
                                readResult[8] == true ? 1 : 0
                            );
                            light_Transducer.State = (Sunny.UI.UILightState)(
                                (read[0] == 1 || read[0] == 2) == true ? 1 : 0
                            );
                            light_Enabled.State = (Sunny.UI.UILightState)(
                                readBoll[0] == true ? 1 : 0
                            );
                            light_Alarm.State = (Sunny.UI.UILightState)(
                                readAlarmBoll[0] == true ? 1 : 0
                            );
                            light_Aotu.State = (Sunny.UI.UILightState)(
                                readResult[7] == true ? 1 : 0
                            );
                            //正限位 x2
                            light_ForwardLimit.State = (Sunny.UI.UILightState)(
                                readResult[1] == true ? 1 : 0
                            );
                            //原点 x3
                            light_OriginalPoint.State = (Sunny.UI.UILightState)(
                                readResult[2] == true ? 1 : 0
                            );
                            //负限位 x4
                            light_NegativeLimit.State = (Sunny.UI.UILightState)(
                                readResult[3] == true ? 1 : 0
                            );
                            //气缸
                            light_AirCylinder.State = (Sunny.UI.UILightState)(
                                readResult2[0] == true ? 1 : 0
                            );
                            //   吸盘 Y6
                            light_SuctionCup.State = (Sunny.UI.UILightState)(
                                readResult2[1] == true ? 1 : 0
                            );
                        })
                    );

                    //读取实时运动状态 M200-M206
                    bool[] realTimeStatus = Instance.modbusMaster.ReadCoils(1, 2200, 6);
                    //读取实时位置
                    uint[] address = Instance.modbusMaster.ReadHoldingRegisters32(1, 200, 1);
                    //读取速度 modbus.ReadInt16( "212" );
                    uint[] speed = Instance.modbusMaster.ReadHoldingRegisters32(1, 212, 1);
                    //读取频率 modbus.ReadInt16( "102" );
                    ushort[] readFrequency = Instance.modbusMaster.ReadHoldingRegisters(1, 102, 1);
                    //读取料盘间距
                    uint[] spaceBetween = Instance.modbusMaster.ReadHoldingRegisters32(1, 214, 1);
                    //左初始化
                    uint[] leftAddress = Instance.modbusMaster.ReadHoldingRegisters32(1, 206, 1);
                    //右初始化
                    uint[] rightAddress = Instance.modbusMaster.ReadHoldingRegisters32(1, 210, 1);
                    BeginInvoke(
                        new Action(() =>
                        {
                            if (realTimeStatus[0] == true)
                                position1.Image = Properties.Resources.区域目标__1_;
                            if (realTimeStatus[1] == true)
                                position2.Image = Properties.Resources.区域目标__1_;
                            if (realTimeStatus[2] == true)
                                position3.Image = Properties.Resources.区域目标__1_;
                            if (realTimeStatus[3] == true)
                                position4.Image = Properties.Resources.区域目标__1_;
                            if (realTimeStatus[4] == true)
                                position5.Image = Properties.Resources.区域目标__1_;
                            if (realTimeStatus[5] == true)
                                position6.Image = Properties.Resources.区域目标__1_;

                            lb_LiveLocation.Text = address[0].ToString();
                            lb_Speed.Text = speed[0].ToString();
                            lb_Frequency.Text = readFrequency[0].ToString();
                            hslGauge1.Value = float.Parse(readFrequency[0].ToString());
                            lb_SpaceBetween.Text = spaceBetween[0].ToString();
                            lb_AutoSpeed.Text = address[0].ToString();
                            lb_LeftAddress.Text = leftAddress[0].ToString();
                            lb_RightAddress.Text = rightAddress[0].ToString();
                        })
                    );
                }
                catch (Exception)
                {
                    Debug.WriteLine("异常");
                }
            }
        }

        /// <summary>
        /// 鼠标按下，开始向左移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pb_Left_MouseDown(object sender, MouseEventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "左移未连接PLC" }, 0);
                return;
            }
            //sender转换成picturebox
            PictureBox senderPictureBox = sender as PictureBox;
            // 向指定线圈地址发送“置位”指令（true 表示激活左移）
            Instance.modbusMaster.WriteSingleCoil(
                1,
                Convert.ToUInt16(senderPictureBox.Tag), // 转换地址为 Modbus 寄存器地址（如 0x0001）
                true // 置位（激活左移）
            );
        }

        /// <summary>
        /// 鼠标抬起，停止向左移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pb_Left_MouseUp(object sender, MouseEventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "左移未连接PLC" }, 0);
                return;
            }
            PictureBox senderPictureBox = sender as PictureBox;
            // 向指定线圈地址发送“置位”指令（true 表示激活左移）
            Instance.modbusMaster.WriteSingleCoil(
                1,
                Convert.ToUInt16(senderPictureBox.Tag), // 转换地址为 Modbus 寄存器地址（如 0x0001）
                false // 复位（停止左移）
            );
        }

        /// <summary>
        /// 鼠标按下，开始向右移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pb_Right_MouseDown(object sender, MouseEventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "右移未连接PLC" }, 0);
                return;
            }
            //sender转换成picturebox
            PictureBox senderPictureBox = sender as PictureBox;
            // 向指定线圈地址发送“置位”指令（true 表示激活右移）
            Instance.modbusMaster.WriteSingleCoil(
                1,
                Convert.ToUInt16(senderPictureBox.Tag), // 转换地址为 Modbus 寄存器地址（如 0x0001）
                true // 置位（激活右移）
            );
        }

        /// <summary>
        /// 鼠标抬起，停止向右移动
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pb_Right_MouseUp(object sender, MouseEventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "右移未连接PLC" }, 0);
                return;
            }
            PictureBox senderPictureBox = sender as PictureBox;
            // 向指定线圈地址发送“置位”指令（true 表示激活右移）
            Instance.modbusMaster.WriteSingleCoil(
                1,
                Convert.ToUInt16(senderPictureBox.Tag), // 转换地址为 Modbus 寄存器地址（如 0x0001）
                false // 复位（停止右移）
            );
        }

        /// <summary>
        /// 回原点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pictureBox11_Click(object sender, EventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请先连接plc" }, 0);
                return;
            }
            Instance.modbusMaster.WriteSingleCoil(1, 2103, true);
            Thread.Sleep(1000);
            Instance.modbusMaster.WriteSingleCoil(1, 2103, false);
        }

        bool q = false;

        /// <summary>
        /// 气缸上下控制 M110
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请先连接plc" }, 0);
                return;
            }
            if (q)
            {
                Instance.modbusMaster.WriteSingleCoil(1, 2110, false);
                q = false;
            }
            else
            {
                Instance.modbusMaster.WriteSingleCoil(1, 2110, true);
                q = true;
            }
            button3.BackColor = q ? Color.Green : Color.White;
        }

        //吸盘控制 M111
        bool x = false;

        /// <summary>
        /// 吸盘控制 M111
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请先连接plc" }, 0);
                return;
            }
            if (x)
            {
                Instance.modbusMaster.WriteSingleCoil(1, 2111, false);
                x = false;
            }
            else
            {
                Instance.modbusMaster.WriteSingleCoil(1, 2111, true);
                x = true;
            }
            button4.BackColor = x ? Color.Green : Color.White;
        }

        /// <summary>
        /// 写入频率
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_WriteFrequency_Click(object sender, EventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请先连接plc" }, 0);
                return;
            }
            try
            {
                // 先验证输入是否为有效数字
                if (!ushort.TryParse(txt_FrequencyText.Text, out ushort value))
                {
                    WriteLog(
                        new Log()
                        {
                            logDateTime = DateTime.Now,
                            logInfo = "输入值格式错误（必须是整数）",
                        },
                        0
                    );
                    return;
                }

                // 再执行写入操作
                Instance.modbusMaster.WriteSingleRegister(1, 102, value);
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "写入成功" }, 1);
            }
            catch (Exception ex)
            {
                WriteLog(
                    new Log() { logDateTime = DateTime.Now, logInfo = $"写入失败：{ex.Message}" },
                    0
                );
            }
        }

        /// <summary>
        /// 变频器频率转换
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void pb_Transducer_Click(object sender, EventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请先连接plc" }, 0);
                return;
            }

            try
            {
                if (pb_Transducer.BackColor == Color.White)
                {
                    // 尝试写入启动指令（1）
                    Instance.modbusMaster.WriteSingleRegister(1, 100, 1);

                    // 若执行到这里，说明写入成功
                    pb_Transducer.BackColor = Color.Gold;
                    WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "启动成功" }, 1);
                }
                else
                {
                    // 尝试写入停止指令（5）
                    Instance.modbusMaster.WriteSingleRegister(1, 100, 5);

                    // 若执行到这里，说明写入成功
                    pb_Transducer.BackColor = Color.White;
                    WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "减速停机成功" }, 1);
                }
            }
            catch (Exception ex)
            {
                // 捕获所有异常（写入失败）
                pb_Transducer.BackColor = Color.Red; // 用红色标记错误状态
                WriteLog(
                    new Log()
                    {
                        logDateTime = DateTime.Now,
                        logInfo = $"写入失败：{ex.Message}" // 记录具体错误原因
                    },
                    0
                );
            }
        }

        //private void button1_Click(object sender, EventArgs e)
        //{
        //    //使用Task线程执行休眠
        //    Task.Run(() =>
        //    {
        //        Thread.Sleep(10000);
        //        this.BeginInvoke(
        //            new Action(() =>
        //            {
        //                button1.Text = "修改完成";
        //            })
        //        );
        //    });
        //}

        /// <summary>
        /// 手自动开关
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void uiTurnSwitch1_ActiveChanged(object sender, EventArgs e)
        {
            if (!Instance.isConnected)
            {
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "请先连接plc" }, 0);
                return;
            }
            if (uiTurnSwitch1.Active)
            {
                Instance.modbusMaster.WriteSingleCoil(
                    1,
                    2105, // 转换地址为 Modbus 寄存器地址（如 0x0001）
                    true // 置位（激活手动）
                );
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "已开启手动" }, 1);
            }
            if (!uiTurnSwitch1.Active)
            {
                Instance.modbusMaster.WriteSingleCoil(
                    1,
                    2105, // 转换地址为 Modbus 寄存器地址（如 0x0001）
                    false // 复位（关闭手动）
                );
                WriteLog(new Log() { logDateTime = DateTime.Now, logInfo = "已关闭手动" }, 1);
            }
        }
    }
}
